
package game;

import java.awt.Cursor;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import javax.swing.* ;
import java.util.ArrayList;
import java.util.Random ;
import java.awt.event.MouseListener ;
import java.awt.event.MouseEvent ;
import java.awt.image.MemoryImageSource;

import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class Impulse extends Game {
    JLabel[] coins;
    JPanel timeDisplay, moneyDisplay ;
    long lastTime, startTime;

    /** The amount of time the subject has to play the game. */
    int time;
    double currMoney, winMoney, decMoney, allHeadsMoney=5.0;
    long currTime;
    boolean[] setcoins; 
    int c = 0;
    int numOfCoins = 0, numOfHeads = 0;
    int totalTime=180,secs = totalTime, timeTaken=0;
    Timer timer = new Timer(1000, new TimeListener());
    String state="init";

    /** Stores all the ImageIcons for all the coins. It may be unnecessary to
     have a seperate ImageIcon instance for every coin, but it works the way
     it is. */
    ArrayList<ImageIcon> coinIcons;

    /** Stores all the flip timers for the coins. */
    ArrayList<Timer> flipTimers;

    /** Stores how long each coin needs to flip. If you want it to flip x times,
     set it to (x * TIME_TO_FLIP). */
    ArrayList<Integer> flipSeconds;
    
    /** Heads or tails state of all the coins. True is heads, false is tails. */
    ArrayList<Boolean> coinsHeadsUp;

    /** How often the flip timer handler should activate, in milliseconds. Also
     represents how long a single coin flip should take. */
    final int TIME_TO_FLIP = 200;

    /** How often the coins flip. */
    final int SECONDS_UNTIL_FLIP = 3;

	// End game constants.
	final int EG_CLICK = 1;
	final int EG_WAIT = 2;
	final int EG_JACKPOT = 3;
    
    ImageIcon heads = new ImageIcon(this.getClass().getResource("/images/heads.jpg"));
    ImageIcon tails = new ImageIcon(this.getClass().getResource("/images/tails.jpg"));

    public Impulse(){
        super();
//        super("",
//              false, //resizable
//              false, //closable
//              false, //maximizable
//              false);//iconifiable
//        javax.swing.plaf.InternalFrameUI ui = this.getUI();
//        ((javax.swing.plaf.basic.BasicInternalFrameUI)ui).setNorthPane(null);

        numOfCoins = 5;
        allHeadsMoney = 10;
        currMoney = 5.00;
        decMoney = 0.5;
        totalTime = 180;
        secs = totalTime;
        
        this.addMouseListener(new Impulse.CheckMouse());
        initComponents();
        initialize() ;
        this.setVisible(true);
        state = "1" ;
        timer.start();
        int min = secs/60;
        int sec = secs%60;
        lblTime.setText(min+":"+((sec<10)?"0":"")+sec);

        hideMouse();
    }

    public Impulse (String params, int currentRep) {
        super();
//        super("",
//              false, //resizable
//              false, //closable
//              false, //maximizable
//              false);//iconifiable
//        javax.swing.plaf.InternalFrameUI ui = this.getUI();
//        ((javax.swing.plaf.basic.BasicInternalFrameUI)ui).setNorthPane(null);

		this.params = params;
		String paramPart[] = params.split (",");
		repNum = currentRep;
		repTot = Integer.parseInt (paramPart[1]);
        numOfCoins = Integer.parseInt (paramPart[2]);
        allHeadsMoney = Double.parseDouble (paramPart[3]);
        currMoney = Double.parseDouble (paramPart[4]);
        decMoney = Double.parseDouble (paramPart[5]);
        totalTime = Integer.parseInt (paramPart[6]);
		secs = totalTime;

        coinIcons = new ArrayList<ImageIcon> (numOfCoins);
        flipTimers = new ArrayList<Timer> (numOfCoins);
        flipSeconds = new ArrayList<Integer> (numOfCoins);
        coinsHeadsUp = new ArrayList<Boolean> (numOfCoins);
        for (int i=0; i<numOfCoins; i++) {
            coinIcons.add (heads);
            flipTimers.add(i, new Timer (TIME_TO_FLIP, new FlipTimerListener(i)));
            flipSeconds.add (i, 0);
            coinsHeadsUp.add (true);
        }

        runner.addMouseListener(new Impulse.CheckMouse());
        this.addMouseListener(new Impulse.CheckMouse());
		this.getGlassPane().addMouseListener(new Impulse.CheckMouse());

        initComponents();
        initialize() ;
        this.setVisible(true);
        state="1";
        timer.start();
        int min = secs/60;
        int sec = secs%60;
        lblTime.setText(min+":"+((sec<10)?"0":"")+sec);

        hideMouse();
    }

    void initialize() {
        coins = new JLabel[numOfCoins] ;
        setcoins = new boolean[numOfCoins];
		for(int i = 0; i < setcoins.length; i++) {
			coins[i] = new JLabel() ;
			Random k = new Random() ;
			//setcoins[i] = k.nextBoolean();
			if (i == 0)
				setcoins[i] = true;
			else
				setcoins[i] = !setcoins[i-1];

			coinsHeadsUp.set(i, setcoins[i]);
			if(setcoins[i]==true) {
				coinIcons.set (i, heads);
				coins[i].setIcon(coinIcons.get(i));
			}
			else {
				coinIcons.set (i, tails);
				coins[i].setIcon(coinIcons.get(i));
			}
			p1.add(coins[i]) ;
		}
		String coinStr = "";
		for (int i=0; i<setcoins.length; i++) {
			coinStr += (setcoins[i] ? 1 : 0);
			if (i != setcoins.length-1)
				coinStr += ",";
		}
		lblTime.setText(Integer.toString(10));
		lblMoney.setText("$ "+String.format("%.2f", currMoney));
    }

    public void RotateCoin (int index) {
        if (coinsHeadsUp.get(index) == false) { // If tails.
            coinsHeadsUp.set (index, true);
            ImageIcon current = getImageIcon("/images/tails2heads.gif");
            coinIcons.set (index, current);
            coins[index].setIcon(coinIcons.get(index));
        }
        else {
            coinsHeadsUp.set (index, false);
            ImageIcon current = getImageIcon("/images/heads2tails.gif");
            coinIcons.set (index, current);
            coins[index].setIcon(coinIcons.get(index));
        }
        coins[index].repaint();
    }

   public void Flip(){
        Random r = new Random();
        
        for (int i=0; i<setcoins.length; i++){
            boolean prevCoin = setcoins[i];
            
            setcoins[i] = r.nextBoolean();
            
            if (prevCoin==false && setcoins[i]==true) {
                int times = (r.nextInt(2)+1)*2 + 1; // 3 or 5.
                flipSeconds.set(i, times*TIME_TO_FLIP);
                // System.err.println("[IMPULSE]: tails to heads");
            }
            else if (prevCoin==true && setcoins[i]==false){
                int times = (r.nextInt(2)+1)*2 + 1; // 3 or 5.
                flipSeconds.set(i, times*TIME_TO_FLIP);
                // System.err.println("[IMPULSE]: heads to tails");
            }
            else if (prevCoin==true && setcoins[i]==true){
                int times = (r.nextInt(2)+2)*2; // 4 or 6.
                flipSeconds.set(i, times*TIME_TO_FLIP);
                // System.err.println("[IMPULSE]: staying heads");
            }
            else if (prevCoin==false && setcoins[i]==false){
                int times = (r.nextInt(2)+2)*2; // 4 or 6.
                flipSeconds.set(i, times*TIME_TO_FLIP);
                // System.err.println("[IMPULSE]: staying tails");
            }

            flipTimers.get(i).start();
        }
    }

    
    public synchronized void addMouseListener(MouseListener l) {
        super.addMouseListener(l);
    }

    /**
     * Defines how often the coin should flip. Starts and finishes the coin
     * animation.
     */
    class FlipTimerListener implements ActionListener {
        int index;

        public FlipTimerListener (int index) {
            this.index = index;
        }

        public void actionPerformed (ActionEvent e) {
            if (flipSeconds.get(index) > 0) {
                flipSeconds.set (index, flipSeconds.get(index)-TIME_TO_FLIP);
                coinIcons.get (index).getImage().flush();
                RotateCoin (index);
            }
            else {
                flipTimers.get(index).stop();

				numOfHeads = 0;
				for (int i = 0; i < setcoins.length; i++) {
					if(setcoins[i] == true)
						numOfHeads++;
				}
				if (numOfHeads == setcoins.length)
					lblResult.setText("You win!");

                ((ImageIcon) coins[index].getIcon()).getImage().flush();
                coinIcons.get (index).getImage().flush();
                if (setcoins[index]) {
                    coinIcons.set(index, new ImageIcon(this.getClass().getResource("/images/heads.jpg")));
                }
                else {
                    coinIcons.set(index, new ImageIcon(this.getClass().getResource("/images/tails.jpg")));
                }
                coins[index].setIcon(coinIcons.get(index));
            }
        }
    }

    /**
     * Loads an ImageIcon. Works to make animated gifs play out completely,
     * unlike calling an ImageIcon constructor with a URL directly.
     * Credit for this code goes to "Jason.smith..." on the Sun Bug Database:
     * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4480705
     *
     * @param name The name of the image we are trying to access.
     * @return The ImageIcon with the given name.
     */
    private static ImageIcon getImageIcon(String name) {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream(256);

            InputStream in = Impulse.class.getResourceAsStream(name);
            try {
                byte[] buffer = new byte[256];
                while(true) {
                  int length = in.read(buffer);
                  if(length == -1)
                  {
                    break;
                  }
                  out.write(buffer, 0, length);
                }
            }
            finally {
                in.close();
            }

            return new ImageIcon(out.toByteArray());
        }
        catch(IOException e) {
            return new ImageIcon();
        }
    }

    class CheckMouse implements MouseListener{
         public void mousePressed(MouseEvent e) { hideMouse(); }
         public void mouseReleased(MouseEvent e) {}
         public void mouseEntered(MouseEvent e) {}
         public void mouseExited(MouseEvent e) {}
         public void mouseClicked(MouseEvent e){
            int modifiers = e.getModifiers();
            if ((modifiers & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
                if(c==0){
                    winMoney = currMoney;
                    timeTaken = totalTime - secs;
                    secs=0;
                    c++;
                    lblResult.setText("You Stopped");
                    lblStop.setVisible(false);
                    try{
                        writeLog (playerId + ",,\"" + params + "\","
							+ repNum + "," + repTot + ","
							+ String.format("$%.2f", winMoney)
							+ ",");

						String coinStr = "";
						for (int i=0; i<setcoins.length; i++) {
							coinStr += (setcoins[i] ? 1 : 0);
							if (i != setcoins.length-1)
								coinStr += ",";
						}
						writeGameLog (playerId + "," + timeTaken + ",\""
							+ coinStr + "\"," + EG_CLICK);
                        totalMoneyWon += winMoney ;
                        System.out.println("G.totalMoneyWon = " + totalMoneyWon) ;
                    }catch(Exception fileExcep){
                        fileExcep.printStackTrace();
                        logError(fileExcep);
                    }
                }
                else {
//                setVisible(false);
//                G.free = true;
                }
            }
        }
    }

    class TimeListener implements ActionListener {
    	 public void actionPerformed(ActionEvent e) {
    		secs--;
            if(secs>0) {
                int min = secs/60;
                int sec = secs%60;
                lblTime.setText(min+":"+((sec<10)?"0":"")+sec);
                currMoney -= decMoney;
                lblMoney.setText("$ "+String.format("%.2f", currMoney));
				timeTaken = totalTime - secs;

                if(secs % SECONDS_UNTIL_FLIP == 0) {
                    numOfHeads = 0;
                    for (int i = 0; i < setcoins.length; i++) {
                        if(setcoins[i] == true) 
                            numOfHeads++;
                    }
					
                    if(numOfHeads == setcoins.length) {
                        secs=-1;
                        
                        winMoney = allHeadsMoney;
                        totalMoneyWon += winMoney ;
						writeLog (playerId + ",,\"" + params + "\","
							+ repNum + "," + repTot + ","
							+ String.format("$%.2f", winMoney)
							+ ",");

						String coinStr = "";
						for (int i=0; i<setcoins.length; i++) {
							coinStr += (setcoins[i] ? 1 : 0);
							if (i != setcoins.length-1)
								coinStr += ",";
						}
						writeGameLog (playerId + "," + timeTaken + ",\""
							+ coinStr + "\"," + EG_JACKPOT);
						c++; // Prevents clicks from registering in the future.
                    }
					else {
						String coinStr = "";
						for (int i=0; i<setcoins.length; i++) {
							coinStr += (setcoins[i] ? 1 : 0);
							if (i != setcoins.length-1)
								coinStr += ",";
						}
						writeGameLog (playerId + "," + timeTaken + ",\""
							+ coinStr + "\"," + EG_WAIT);

						Flip();
					}
                }
            }

            if(secs==0) {
                winMoney = 0.0 ;
                lblStop.setVisible(false);
                lblResult.setText("Sorry, your time is up.");
                state="end";
				writeLog (playerId + ",,\"" + params + "\","
					+ repNum + "," + repTot + ",TimeOut,TimeOut");
				String coinStr = "";
				for (int i=0; i<setcoins.length; i++) {
					coinStr += (setcoins[i] ? 1 : 0);
					if (i != setcoins.length-1)
						coinStr += ",";
				}
				writeGameLog (playerId + "," + timeTaken + ",\"" + coinStr
					+ "\",TimeOut");
                System.out.println("G.totalMoneyWon = " + totalMoneyWon) ;
            }

            if(secs==-6) {
                timer.stop();
                try {
                    setVisible(false);
                    free=true;
                } catch(Exception ex) {
                    ex.printStackTrace();
                    logError(ex);
                }
            }
    	}
    }

    private void hideMouse() {
        int[] pixels = new int[16 * 16];
        Image image = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(16, 16, pixels, 0, 16));
        Cursor transparentCursor = Toolkit.getDefaultToolkit().createCustomCursor(image, new Point(0, 0), "invisibleCursor");
        this.getGlassPane().setCursor(transparentCursor);
		this.getGlassPane().setVisible(true);
        runner.setCursor(transparentCursor);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPanel2 = new javax.swing.JPanel();
        lblTime = new javax.swing.JLabel();
        jPanel3 = new javax.swing.JPanel();
        lblMoney = new javax.swing.JLabel();
        p1 = new javax.swing.JPanel();
        lblResult = new javax.swing.JLabel();
        lblStop = new javax.swing.JLabel();

        setBackground(new java.awt.Color(255, 255, 255));
        setBorder(null);
        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setMaximumSize(new java.awt.Dimension(800, 600));
        setMinimumSize(new java.awt.Dimension(800, 600));
        setPreferredSize(new java.awt.Dimension(800, 600));

        jPanel2.setBackground(new java.awt.Color(255, 255, 255));
        jPanel2.setPreferredSize(new java.awt.Dimension(121, 285));

        lblTime.setFont(new java.awt.Font("Calibri", 1, 36));
        lblTime.setForeground(new java.awt.Color(153, 102, 0));
        lblTime.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/hrGlass.png"))); // NOI18N
        lblTime.setText("3:00");

        org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .add(lblTime, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 286, Short.MAX_VALUE)
                .addContainerGap())
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel2Layout.createSequentialGroup()
                .add(15, 15, 15)
                .add(lblTime, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 70, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(16, Short.MAX_VALUE))
        );

        jPanel3.setBackground(new java.awt.Color(255, 255, 255));

        lblMoney.setFont(new java.awt.Font("Trebuchet MS", 1, 24));
        lblMoney.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);

        org.jdesktop.layout.GroupLayout jPanel3Layout = new org.jdesktop.layout.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .add(lblMoney, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 220, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(32, Short.MAX_VALUE))
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .add(lblMoney, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE)
                .addContainerGap())
        );

        p1.setBackground(new java.awt.Color(255, 255, 255));

        lblResult.setFont(new java.awt.Font("Calibri", 1, 30));
        lblResult.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);

        lblStop.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/redStop.png"))); // NOI18N

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(layout.createSequentialGroup()
                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(lblResult, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
                            .add(p1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
                            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                                .add(jPanel2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 306, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 212, Short.MAX_VALUE)
                                .add(jPanel3, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
                        .addContainerGap())
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                        .add(lblStop)
                        .add(271, 271, 271))))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                    .add(jPanel3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .add(jPanel2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 101, Short.MAX_VALUE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(p1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 293, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(lblResult, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 53, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(lblStop)
                .addContainerGap(18, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        try {
            JFrame main = new JFrame();
            JDesktopPane dPane = new JDesktopPane();
            Impulse frame = new Impulse();
            main.setSize(820, 620);
            dPane.add(frame);
            main.add(dPane);
            main.setVisible(true);
            dPane.setVisible(true);
            frame.setSelected(true);
            frame.setVisible(true);
            } catch(Exception ex) {
            ex.printStackTrace();
            }

    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JLabel lblMoney;
    private javax.swing.JLabel lblResult;
    private javax.swing.JLabel lblStop;
    private javax.swing.JLabel lblTime;
    private javax.swing.JPanel p1;
    // End of variables declaration//GEN-END:variables

}